Skip to main content
Glama

Axion Planetary MCP

by Dhenenjay
advancedEarthEngineTools.tsβ€’18.9 kB
import * as ee from '@google/earthengine'; import { z } from 'zod'; // Re-export the basic initialization function import { initializeEarthEngine } from './earthengineTools'; export { initializeEarthEngine }; // Type definitions interface EarthEngineError { error: string; message: string; } /** * Get an Earth Engine image collection * @param collectionId ID of the collection (e.g., "COPERNICUS/S2") * @returns Promise with image collection info */ export const getImageCollection = async (collectionId: string): Promise<any | EarthEngineError> => { try { const collection = new ee.ImageCollection(collectionId); return new Promise((resolve, reject) => { collection.getInfo((info: any) => { resolve(info); }); }); } catch (error) { return { error: 'COLLECTION_ERROR', message: `Error getting collection: ${error instanceof Error ? error.message : String(error)}` }; } }; /** * Filter an image collection by date range * @param collectionId ID of the collection * @param startDate Start date (YYYY-MM-DD) * @param endDate End date (YYYY-MM-DD) * @returns Promise with filtered collection info */ export const filterCollectionByDate = async ( collectionId: string, startDate: string, endDate: string ): Promise<any | EarthEngineError> => { try { const collection = new ee.ImageCollection(collectionId) .filterDate(startDate, endDate); return new Promise((resolve, reject) => { collection.getInfo((info: any) => { resolve(info); }); }); } catch (error) { return { error: 'FILTER_DATE_ERROR', message: `Error filtering by date: ${error instanceof Error ? error.message : String(error)}` }; } }; /** * Filter an image collection by geographic bounds * @param collectionId ID of the collection * @param geometry GeoJSON geometry for the region * @returns Promise with filtered collection info */ export const filterCollectionByBounds = async ( collectionId: string, geometry: any ): Promise<any | EarthEngineError> => { try { const region = new ee.Geometry(geometry); const collection = new ee.ImageCollection(collectionId) .filterBounds(region); return new Promise((resolve, reject) => { collection.getInfo((info: any) => { resolve(info); }); }); } catch (error) { return { error: 'FILTER_BOUNDS_ERROR', message: `Error filtering by bounds: ${error instanceof Error ? error.message : String(error)}` }; } }; /** * Filter an image collection by metadata property * @param collectionId ID of the collection * @param property Property name * @param operator Operator for comparison (e.g., "less_than", "equals") * @param value Value to compare against * @returns Promise with filtered collection info */ export const filterCollectionByMetadata = async ( collectionId: string, property: string, operator: string, value: any ): Promise<any | EarthEngineError> => { try { const collection = new ee.ImageCollection(collectionId) .filterMetadata(property, operator, value); return new Promise((resolve, reject) => { collection.getInfo((info: any) => { resolve(info); }); }); } catch (error) { return { error: 'FILTER_METADATA_ERROR', message: `Error filtering by metadata: ${error instanceof Error ? error.message : String(error)}` }; } }; /** * Calculate a normalized difference index (e.g., NDVI) * @param imageId ID of the image * @param bandA First band name * @param bandB Second band name * @param visParams Visualization parameters * @returns Promise with index image map */ export const calculateIndex = async ( imageId: string, bandA: string, bandB: string, visParams: Record<string, any> = {} ): Promise<any | EarthEngineError> => { try { const image = new ee.Image(imageId) .normalizedDifference([bandA, bandB]); return new Promise((resolve) => { try { const map = image.getMap(visParams); if (!map) { resolve({ error: 'INDEX_ERROR', message: 'Earth Engine returned null or undefined result. The dataset may not be accessible, bands may be invalid, or you may need to authenticate first.' }); return; } resolve(map); } catch (callbackError) { resolve({ error: 'INDEX_ERROR', message: `Error in index calculation callback: ${callbackError instanceof Error ? callbackError.message : String(callbackError)}` }); } }); } catch (error) { return { error: 'INDEX_ERROR', message: `Error calculating index: ${error instanceof Error ? error.message : String(error)}` }; } }; /** * Apply a cloud mask to an image using simple cloud score * @param landsatImageId ID of a Landsat image * @param cloudThreshold Threshold for cloud score (0-100) * @param visParams Visualization parameters * @returns Promise with masked image map */ export const applyCloudMask = async ( landsatImageId: string, cloudThreshold: number, visParams: Record<string, any> = {} ): Promise<any | EarthEngineError> => { try { const image = new ee.Image(landsatImageId); const cloudScore = ee.Algorithms.Landsat.simpleCloudScore(image); const mask = (cloudScore.select('cloud') as any).lt(cloudThreshold); const maskedImage = image.updateMask(mask); return new Promise((resolve) => { try { const map = maskedImage.getMap(visParams); if (!map) { resolve({ error: 'CLOUD_MASK_ERROR', message: 'Earth Engine returned null or undefined result. The dataset may not be accessible or you may need to authenticate first.' }); return; } resolve(map); } catch (callbackError) { resolve({ error: 'CLOUD_MASK_ERROR', message: `Error in cloud mask callback: ${callbackError instanceof Error ? callbackError.message : String(callbackError)}` }); } }); } catch (error) { return { error: 'CLOUD_MASK_ERROR', message: `Error applying cloud mask: ${error instanceof Error ? error.message : String(error)}` }; } }; /** * Create a composite image from a collection (median, mean, etc.) * @param collectionId ID of the collection * @param method Composite method ('median', 'mean', 'min', 'max', 'mosaic') * @param filterParams Optional date and region filters * @param visParams Visualization parameters * @returns Promise with composite image map */ export const createComposite = async ( collectionId: string, method: 'median' | 'mean' | 'min' | 'max' | 'mosaic' = 'median', filterParams: { startDate?: string, endDate?: string, geometry?: any, cloudCoverMax?: number } = {}, visParams: Record<string, any> = {} ): Promise<any | EarthEngineError> => { try { let collection = new ee.ImageCollection(collectionId); // Apply filters if provided if (filterParams.startDate && filterParams.endDate) { collection = collection.filterDate(filterParams.startDate, filterParams.endDate); } if (filterParams.geometry) { const region = new ee.Geometry(filterParams.geometry); collection = collection.filterBounds(region); } if (filterParams.cloudCoverMax !== undefined) { collection = collection.filterMetadata('CLOUD_COVER', 'less_than', filterParams.cloudCoverMax); } // Create composite based on method let composite: ee.Image; switch (method) { case 'median': composite = collection.median(); break; case 'mean': composite = collection.mean(); break; case 'min': composite = collection.min(); break; case 'max': composite = collection.max(); break; case 'mosaic': composite = collection.mosaic(); break; default: composite = collection.median(); } return new Promise((resolve) => { try { const map = composite.getMap(visParams); if (!map) { resolve({ error: 'COMPOSITE_ERROR', message: 'Earth Engine returned null or undefined result. The collection may be empty, filters may be too restrictive, or you may need to authenticate first.' }); return; } resolve(map); } catch (callbackError) { resolve({ error: 'COMPOSITE_ERROR', message: `Error in composite callback: ${callbackError instanceof Error ? callbackError.message : String(callbackError)}` }); } }); } catch (error) { return { error: 'COMPOSITE_ERROR', message: `Error creating composite: ${error instanceof Error ? error.message : String(error)}` }; } }; /** * Export an image to Google Drive * @param imageId ID of the image or an image object * @param exportParams Export parameters (description, folder, region, scale) * @returns Promise with export task info */ export const exportImageToDrive = async ( imageId: string, exportParams: { description: string, folder: string, region: any, scale: number, maxPixels?: number } ): Promise<any | EarthEngineError> => { try { const image = new ee.Image(imageId); const region = new ee.Geometry(exportParams.region); try { const task = ee.batch.Export.image.toDrive({ image: image, description: exportParams.description, folder: exportParams.folder, fileNamePrefix: exportParams.description, region: region, scale: exportParams.scale, maxPixels: exportParams.maxPixels || 1e9 }); task.start(); if (!task || !task.id) { return { error: 'EXPORT_ERROR', message: 'Failed to create export task. You may need to authenticate first.' }; } return { taskId: task.id, status: 'STARTED', description: exportParams.description }; } catch (taskError) { return { error: 'EXPORT_ERROR', message: `Error starting export task: ${taskError instanceof Error ? taskError.message : String(taskError)}` }; } } catch (error) { return { error: 'EXPORT_ERROR', message: `Error exporting image: ${error instanceof Error ? error.message : String(error)}` }; } }; /** * Get the status of an export task * @param taskId ID of the export task * @returns Promise with task status */ export const getExportTaskStatus = async ( taskId: string ): Promise<any | EarthEngineError> => { try { return new Promise((resolve) => { try { ee.data.getTaskStatus([taskId], (statusResponse: any) => { // Check if statusResponse is undefined or null if (!statusResponse) { resolve({ error: 'TASK_STATUS_ERROR', message: 'Earth Engine returned null or undefined status. The task ID may be invalid or you may need to authenticate first.' }); return; } resolve(Array.isArray(statusResponse) ? statusResponse[0] : statusResponse); }); } catch (callbackError) { resolve({ error: 'TASK_STATUS_ERROR', message: `Error in task status callback: ${callbackError instanceof Error ? callbackError.message : String(callbackError)}` }); } }); } catch (error) { return { error: 'TASK_STATUS_ERROR', message: `Error getting task status: ${error instanceof Error ? error.message : String(error)}` }; } }; /** * Get all active or completed Earth Engine tasks * @returns Promise with list of all tasks */ export const getAllExportTasks = async (): Promise<any | EarthEngineError> => { try { return new Promise((resolve) => { try { // Use the lower-level API call to get the task list ee.data.getTaskList({}, (taskList: any) => { // Check if taskList is undefined or null if (!taskList) { resolve({ error: 'TASK_LIST_ERROR', message: 'Earth Engine returned null or undefined task list. You may need to authenticate first.' }); return; } resolve(taskList); }); } catch (callbackError) { resolve({ error: 'TASK_LIST_ERROR', message: `Error in task list callback: ${callbackError instanceof Error ? callbackError.message : String(callbackError)}` }); } }); } catch (error) { return { error: 'TASK_LIST_ERROR', message: `Error getting task list: ${error instanceof Error ? error.message : String(error)}` }; } }; /** * Run a time series analysis on an image collection for a region * @param collectionId ID of the collection * @param geometry GeoJSON geometry for the region * @param startDate Start date (YYYY-MM-DD) * @param endDate End date (YYYY-MM-DD) * @param bands Bands to analyze * @returns Promise with time series data */ export const timeSeriesAnalysis = async ( collectionId: string, geometry: any, startDate: string, endDate: string, bands: string[] ): Promise<any | EarthEngineError> => { try { const region = new ee.Geometry(geometry); const collection = (new ee.ImageCollection(collectionId) .filterDate(startDate, endDate) .filterBounds(region) as any) .select(bands); // For each image in the collection, calculate the mean value in the region const reducer = ee.Reducer.mean(); return new Promise((resolve) => { collection.getInfo((collInfo: any) => { // Use the date from each image for the time series const timeSeries: { date: string, values: Record<string, number> }[] = []; // Process each image individually to get stats const processImages = async () => { for (const img of collInfo.features) { const imgId = img.id; const date = img.properties['system:time_start']; const formattedDate = new Date(date).toISOString().split('T')[0]; const image = new ee.Image(imgId); const stats = await new Promise<any>((resolveStats) => { image.reduceRegion({ reducer: reducer, geometry: region, scale: 30 // Adjust scale as needed }).getInfo((imgStats: any) => { resolveStats(imgStats); }); }); timeSeries.push({ date: formattedDate, values: stats }); } resolve({ collectionId, startDate, endDate, bands, timeSeries }); }; processImages(); }); }); } catch (error) { return { error: 'TIME_SERIES_ERROR', message: `Error in time series analysis: ${error instanceof Error ? error.message : String(error)}` }; } }; /** * Create a custom band math expression * @param imageId ID of the image * @param expression Math expression (e.g., "(b('B4') - b('B3')) / (b('B4') + b('B3'))") * @param visParams Visualization parameters * @returns Promise with expression result map */ export const applyExpression = async ( imageId: string, expression: string, visParams: Record<string, any> = {} ): Promise<any | EarthEngineError> => { try { const image = new ee.Image(imageId); const expressionResult = image.expression(expression); return new Promise((resolve) => { try { const map = expressionResult.getMap(visParams); if (!map) { resolve({ error: 'EXPRESSION_ERROR', message: 'Earth Engine returned null or undefined result. The expression may be invalid, the dataset may not be accessible, or you may need to authenticate first.' }); return; } resolve(map); } catch (callbackError) { resolve({ error: 'EXPRESSION_ERROR', message: `Error in expression callback: ${callbackError instanceof Error ? callbackError.message : String(callbackError)}` }); } }); } catch (error) { return { error: 'EXPRESSION_ERROR', message: `Error applying expression: ${error instanceof Error ? error.message : String(error)}` }; } }; /** * Cancel an Earth Engine export task * @param taskId ID of the export task * @returns Promise with result of the cancellation */ export const cancelExportTask = async ( taskId: string ): Promise<any | EarthEngineError> => { try { return new Promise((resolve) => { try { ee.data.cancelTask(taskId, (response: any) => { // Check if response is undefined or null if (!response) { resolve({ error: 'TASK_CANCEL_ERROR', message: 'Earth Engine returned null or undefined response. The task ID may be invalid or you may need to authenticate first.' }); return; } resolve({ taskId, success: true, status: 'CANCELLED', response }); }); } catch (callbackError) { resolve({ error: 'TASK_CANCEL_ERROR', message: `Error in cancel task callback: ${callbackError instanceof Error ? callbackError.message : String(callbackError)}` }); } }); } catch (error) { return { error: 'TASK_CANCEL_ERROR', message: `Error cancelling task: ${error instanceof Error ? error.message : String(error)}` }; } }; // Schema definitions for parameters export const CollectionIdSchema = z.string().describe('Earth Engine image collection ID (e.g., "COPERNICUS/S2")'); export const DateSchema = z.string().describe('Date in YYYY-MM-DD format'); export const BandNameSchema = z.string().describe('Band name (e.g., "B4", "B8", "NDVI")'); export const BandNamesSchema = z.array(z.string()).describe('List of band names'); export const MethodSchema = z.enum(['median', 'mean', 'min', 'max', 'mosaic']).describe('Method for composite creation'); export const ExpressionSchema = z.string().describe('Math expression using band values'); export const TaskIdSchema = z.string().describe('Earth Engine export task ID'); export const CloudThresholdSchema = z.number().min(0).max(100).describe('Cloud threshold (0-100)'); // Re-export schemas from basic tools export { PrivateKeySchema, DatasetIdSchema, VisParamsSchema, GeometrySchema, ScaleSchema, QuerySchema } from './earthengineTools';

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Dhenenjay/axion-planetary-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server